﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper.DBContext;
using Guoc.BigMall.WebService.Dto;
using Guoc.BigMall.Domain.Entity;
using Guoc.BigMall.Infrastructure;
using Guoc.BigMall.Infrastructure.WeChat;
using Guoc.BigMall.Infrastructure.WeChat.Entitys;
using Guoc.BigMall.WebService;
using Guoc.BigMall.Infrastructure.WeChat.JsSdk;
using Guoc.BigMall.Infrastructure.Payment;

namespace Guoc.BigMall.WebService.Implement
{
    public class WechatService : IWechatService
    {
        IUserContextService _userContext;
        IDBContext _db;
        private static object locker = new object();
        WechatAccount _wxAccount;
        public WechatService(IDBContext dbContext, IUserContextService userContext)
        {
            this._db = dbContext;
            _userContext = userContext;

            

        }

        /// <summary>
        ///  
        /// </summary>
        /// <param name="storeCode"></param>
        private void GetWxAccount(string storeCode) {
            // 查询当前appid 和secret
            var wxAccount = _db.Table<WechatAccount>().FirstOrDefault(n => n.StoreCode == storeCode);
            if (wxAccount == null)
            {
                throw new FriendlyException("请配置微信账户appid");
            }

            _wxAccount = wxAccount;
        }

        public string GetAccessToken(string storeCode)
        {
            GetWxAccount(storeCode);
            string appId = _wxAccount.AppId;
            string secret = _wxAccount.AppSecret;
            string token = "";
            int offTime = 60;
            var accessToken = _db.Table<WechatAccountToken>().FirstOrDefault(n => n.AppId == appId && n.TokenType == "AccessToken");
            if (accessToken == null)
            {
                var response = WeChatApi.GetToken(appId, secret);
                if (response != null && !string.IsNullOrEmpty(response.access_token))
                {
                    WechatAccountToken entity = new WechatAccountToken()
                    {
                        AppId = appId,
                        Token = response.access_token,
                        ExpiresIn = response.expires_in ,
                        TokenType = "AccessToken"

                    };
                    _db.Insert(entity);
                    _db.SaveChange();
                    token = entity.Token;
                }
            }
            else
            {
                // 当前时间已经过期,重新获取token并更新数据库记录        ?? 7150
                if (accessToken.LastGetAt.AddSeconds(accessToken.ExpiresIn - offTime) < DateTime.Now)
                {
                    lock (locker)
                    {
                        var response = WeChatApi.GetToken(appId, secret);
                        accessToken.Token = response.access_token;
                        accessToken.ExpiresIn = response.expires_in - offTime;//设置时间偏移量5分钟
                        accessToken.LastGetAt = DateTime.Now;
                        _db.Update(accessToken);
                        _db.SaveChange();
                    }
                }
                token = accessToken.Token;
            }
            return token;
        }

        public AccessTokenWeb GetAccessTokenByCode(string code, string appid, string appSecret)
        {
            var tokenResult = WeChatApi.GetAccessTokenByCode(appid, appSecret, code);
            return tokenResult;
        }

        public WeChatUserInfo GetWeChatUser(string accessToken, string openid)
        {
            var userInfo = WeChatApi.GetUserInfo(accessToken, openid);
            if (string.IsNullOrEmpty(userInfo.openid))
            {
                throw new Exception("获取openid 失败");
            }
            //WechatUser entity = _db.Table<WechatUser>().FirstOrDefault(n => n.OpenId == openid);
            //if (entity == null) {
            //    entity = new WechatUser()
            //    {
            //        OpenId = openid,
            //        NickName = userInfo.nickname,
            //        Sex = userInfo.sex,
            //        HeadImage = userInfo.headimgurl,
            //        UnionId = userInfo.unionid,
            //        Subscribe = 1,
            //    };
            //    _db.Insert(entity);
            //    _db.SaveChange();
            //}
            //return entity;           
            return userInfo;
        }

        /// <summary>
        /// 构建js sdk config 参数：
        /// </summary>
        /// <param name="url"></param>
        /// <param name="storeCode"></param>
        /// <returns></returns>
        public JsConfigResult BuildJsSdkConfig(string url, string storeCode)
        {
            var ticket = GetJsTicket(storeCode);
            // 生成签名,key 必须都是小写
            AbstractRequest data = new AbstractRequest();
            data.Add("noncestr", data.GenerateNonceStr());           
            data.Add("jsapi_ticket", ticket);
            data.Add("timestamp", data.GenerateTimeStamp());
            data.Add("url", url);

            var sign = data.MakeJsSign(AbstractRequest.SIGN_TYPE_SHA1);
            // 构造返回对象
            JsPayResult shareResult = new JsPayResult()
            {
                appId = _wxAccount.AppId,
                nonceStr = data.GetValue<string>("noncestr"),
                timestamp = data.GetValue<string>("timestamp"),
                signature = sign
            };

            return shareResult;
        }

        public string GetJsTicket(string storeCode)
        {
            GetWxAccount(storeCode);
            string appId = _wxAccount.AppId;
            int offTime = 60;
            var accountToken = _db.Table<WechatAccountToken>().FirstOrDefault(n => n.AppId == appId && n.TokenType == "JsTicket");
            // 第一次访问
            if (accountToken == null)
            {
                var accessToken = GetAccessToken(storeCode);
                var response = WeChatApi.GetJsTicket(accessToken);
                if (response.errcode != "0") {
                    throw new FriendlyException("获取js ticket 错误");
                }
                WechatAccountToken entity = new WechatAccountToken()
                {
                    AppId = appId,
                    Token = response.ticket,
                    ExpiresIn = response.expires_in, 
                    TokenType = "JsTicket",
                };
                _db.Insert(entity);
                _db.SaveChange();
                return  entity.Token;
            }

            // 当前时间已经过期,重新获取token并更新数据库记录  // 已过期,刷新过期时间
            if (accountToken.LastGetAt.AddSeconds(accountToken.ExpiresIn - offTime) < DateTime.Now)
            {
                var accessToken = GetAccessToken(storeCode);
                var response = WeChatApi.GetJsTicket(accessToken);
                accountToken.Token = response.ticket;
                accountToken.ExpiresIn = response.expires_in;
                accountToken.LastGetAt = DateTime.Now;
                _db.Update(accountToken);
                _db.SaveChange();
            }

            return accountToken.Token;
        }
    }
}
